package com.yizisu.basemvvm.mvvm.mvvm_helper

import com.yizisu.basemvvm.logI
import java.io.*

/**
 * 若红楼梦空，亦初心不变
 * 作者：thinker
 * 包名：com.yizisu.basemvvm.mvvm.mvvm_helper
 * 时间：2019/6/4 9:30
 * 描述：
 */
object MessageBus {
    /**
     * 消息接口集合
     */
    private val receiverList = mutableListOf<MessageBusInterface>()
    /**
     * 最近一次的值
     */
    private var stickyValue = mutableMapOf<Any?, Int>()

    /**
     * 注册
     */
    fun register(receiver: MessageBusInterface) {
        if (!receiverList.contains(receiver)) {
            receiverList.add(receiver)
            val oldStickyValue = stickyValue.toMap()
            for ((value, code) in oldStickyValue) {
                receiver.onMessageBus(value, code)
            }
        }
    }

    /**
     * 清除数据防止内存泄漏
     */
    fun clearStickyValue(event: Any?) {
        stickyValue.remove(event)
    }

    /**
     * 清除数据防止内存泄漏
     */
    fun clearAllStickyValue() {
        stickyValue.clear()
    }

    /**
     * 移除注册
     */
    fun unRegister(receiver: MessageBusInterface) {
        if (receiverList.contains(receiver)) {
            receiverList.remove(receiver)
        }
    }

    /**
     * 将值发送出去
     * isSticky 新注册的第一个接口是否接受此数据
     */
    fun post(code: Int, event: Any?, isSticky: Boolean = false) {
        if (isSticky) {
            postStaickValue(code, event)
        } else {
            clearStickyValue(code)
        }
        receiverList.forEach {
            it.onMessageBus(event, code)
        }
    }

    /**
     * 赋值最新的一次值
     * 每次新添加的监听者，都可以接受到最新的一次值
     */
    fun postStaickValue(code: Int, event: Any?) {
        stickyValue[event] = code
    }

    /**
     *   isClone 是否克隆，true 发送一个新的对象 false 发送源对象
     */
    fun postStaickValue(code: Int, event: Serializable?, isClone: Boolean) {
        stickyValue[if (isClone) copyObj(event) else event] = code
    }

    /**
     *   isClone 是否克隆，true 发送一个新的对象 false 发送源对象
     */
    fun postStaickValue(code: Int, event: List<Serializable>?, isClone: Boolean) {
        stickyValue[if (isClone) copyObj(event) else event] = code
    }

    /**
     * 将值发送出去
     *  isSticky 新注册的第一个接口是否接受此数据
     */
    fun post(code: Int, event: Any?, isSticky: Boolean = false, vararg mark: Class<*>) {
        if (isSticky) {
            postStaickValue(code, event)
        }
        if (mark.count() == 0) {
            receiverList.forEach {
                it.onMessageBus(event, code)
            }
        } else {
            receiverList.forEach {
                mark.forEach { cls ->
                    if (it.javaClass == cls) {
                        it.onMessageBus(event, code)
                    }
                }
            }
        }
    }

    /**
     * 将值发送出去
     *  isSticky 新注册的第一个接口是否接受此数据
     *  isClone 是否克隆，true 发送一个新的对象 false 发送源对象
     */
    fun post(
        code: Int,
        event: Serializable?,
        isClone: Boolean,
        isSticky: Boolean = false,
        vararg mark: Class<*>
    ) {
        if (isClone) {
            post(code, copyObj(event), isSticky, *mark)
        } else {
            post(code, event, isSticky, *mark)
        }
    }

    /**
     * 将值发送出去
     *  isSticky 新注册的第一个接口是否接受此数据
     *  isClone 是否克隆，true 发送一个新的对象 false 发送源对象
     */
    fun post(
        code: Int,
        event: List<Serializable>?,
        isClone: Boolean,
        isSticky: Boolean = false,
        vararg mark: Class<*>
    ) {
        if (isClone) {
            post(code, copyObj(event), isSticky, *mark)
        } else {
            post(code, event, isSticky, *mark)
        }
    }

    /**
     * 复制对象
     * 后续测试如果卡顿可以将这段代码放在子线程运行
     */
    @Synchronized
    private fun copyObj(event: Any?): Any? {
        event ?: return event
        val startTime = System.currentTimeMillis()
        val baos = ByteArrayOutputStream()
        val out = ObjectOutputStream(baos)
        out.writeObject(event)
        out.close()
        val ins = ObjectInputStream(ByteArrayInputStream(baos.toByteArray()))
        val newEvent = ins.readObject()
        ins.close()
        val end = System.currentTimeMillis()
        logI("花费时间：${end - startTime}")
        return newEvent
    }
}